/* ********************************************************************************************
*  Alvin Baldemeca
*  Tetris Project
*  Course: TCSS 305 , Alan Fowler
*  Term: Spring 2012
*  UNIVERISTY OF WASHINGTON TACOMA
*
*
**********************************************************************************************/
package view;

import controller.Board;
import gui.actions.AboutAction;
import gui.actions.AssignKeyAction;
import gui.actions.CustomizeKeysAction;
import gui.actions.DizzyAction;
import gui.actions.DownAction;
import gui.actions.DropAction;
import gui.actions.EndGameAction;
import gui.actions.GridBaordAction;
import gui.actions.LeftAction;
import gui.actions.PauseAction;
import gui.actions.PracticeAction;
import gui.actions.QuitAction;
import gui.actions.RightAction;
import gui.actions.RotateAction;
import gui.actions.SelectLevelAction;
import gui.actions.StartAction;
import gui.actions.SwapPieceAction;
import gui.actions.UndoPieceAction;

import gui.actions.paint.ClearAction;
import gui.actions.paint.ColorAction;
import gui.actions.paint.EllipseAction;
import gui.actions.paint.GridAction;
import gui.actions.paint.LineAction;
import gui.actions.paint.PaintOnAction;
import gui.actions.paint.PencilAction;
import gui.actions.paint.RectangleAction;
import gui.actions.paint.ShowPanelAction;
import gui.actions.paint.ThicknessAction;
import gui.actions.paint.UndoAction;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.KeyStroke;
import javax.swing.Timer;

import view.container.PowerPaintToolBar;
import view.container.TetrisFrame;
import view.container.TetrisPaintPanel;
import view.menu.FileMenu;
import view.menu.HelpMenu;
import view.menu.LevelMenu;
import view.menu.OptionsMenu;
import view.menu.ThicknessMenu;
import view.menu.ToolsMenu;





/**
 * This class is the GUI for the tetris game.  It contains the frames, containers
 * listeners. It is the next class below main that controls and contains all the 
 * component in the tetris game.
 * @author Alvin Baldemeca
 * @version 5/24/2012
 *
 */
public class TetrisGUI 
{
  
  /**
   * The grid line spacing for the drawing panel.
   */
  private static final int GRIDLINE_SPACING = 10;
  /**
   * The height of the tetris board used to create the board and its graphics.
   */
  private static final int TETRIS_BOARD_HEIGHT = 20;
  
  /**
   * The width of the tetris board used to create the board and its graphics.
   */
  private static final int TETRIS_BOARD_WIDTH = 10;
  
  /**
   * The initial delay (in milliseconds) for the move timer.
   */
  private static final int INITIAL_DELAY = 1000;
  
  /**
   * Then number of lines that need to be cleared to get to the next level.
   */
  private static final int NEXT_LEVEL = 20;
  
  /**
   * The time in milliseconds to speed up the timer.
   */
  private static final int SPEED_UP = 48;
  
  /**
   * The minimus size the frame can be set to.
   */
  
  private static final Dimension MINIMUM_SIZE = new Dimension(200, 300);
  /**
   * The pixel thickness for the tetris paint to use that is 1 pixel thick. 
   */
  private static final int ONE_PIXEL = 1;
  
  /**
   * The pixel thickness for the tetris paint to use that is 1 pixel thick. 
   */
  private static final int TWO_PIXEL = 2;
  
  /**
   * The pixel thickness for the tetris paint to use that is 1 pixel thick. 
   */
  private static final int FOUR_PIXEL = 4;
  
  /**
   * The pixel thickness for the tetris paint to use that is 1 pixel thick. 
   */
  private static final int EIGHT_PIXEL = 8;
  
  /**
   * The default pencil pixel thickness when the program starts. 
   */
  private static final float INITIAL_PENCIL_THICKNESS = 3f;
  /**
   * The number of user assigned keys for the user to configure.
   */
  private static final int NUMBER_OF_USER_ASSIGNED_KEYS = 5;
  
  /**
   * The number of tetris buttons to add to the panel.
   */
  private static final int NUMBER_OF_TETRIS_BUTTONS = 4;
  
  /**
   * The number of level that a person can select from the menu.
   */
  private static final int NUMBER_OF_LEVELS = 20;
  
  /**
   * The y-coordinate to set the focus on the content pane.
   */
  private static final int FOCUS_Y = 50;
  

  /**
   * The index of the action in the keyboard actions array.
   */
  private static final int LEFT = 0;
    
  /**
   * The index of the action in the keyboard actions array.
   */
  private static final int  RIGHT = 1;
    
  /**
   * The index of the action in the keyboard actions array.
   */
  private static final int  DOWN = 2;
    
  /**
   * The index of the action in the keyboard actions array.
   */
  private static final int  ROTATE = 3;
    
  /**
   * The index of the action in the keyboard actions array.
   */
  private static final int DROP = 4;
    
  /**
   * The index of the action in the keyboard actions array.
   */
  private static final int  START_GAME = 5;
    
  /**
   * The index of the action in the keyboard actions array.
   */
  private static final int  ABOUT = 6;
    
  /**
   * The index of the action in the keyboard actions array.
   */
  private static final int  END = 7;
    
  /**
   * The index of the action in the keyboard actions array.
   */
  private static final int  PAUSE = 8;
   
  /**
   * The index of the action in the keyboard actions array.
   */
  private static final int  SWAP = 9;
    
  /**
   * The index of the action in the keyboard actions array.
   */
  private static final int  PRACTICE = 10;
    
  /**
   * The index of the action in the keyboard actions array.
   */
  private static final int  UNDO = 11;
 
  /**
   * The tetris board to be played on.
   */
  private Board my_tetris_board = new Board(TETRIS_BOARD_HEIGHT, TETRIS_BOARD_WIDTH);
  
  /**
   * The panel used to interface with the main board, which paints the
   * graphics to show the game to the user.
   */
  private final TetrisBoardPanel my_tetris_board_panel;
  
  
  /**
   * The drawing panel for paint on.
   */
  private final TetrisPaintPanel my_tetris_paint_panel;
  
  /**
   * The list of boards played used to save and load the state of the game.
   */
  private final List<Board> my_board_list; 

  /**
   * The list of actions to be added to the file menu.
   */
  private Action[] my_file_menu_actions;
  
  /**
   * The container that will hold the option menu actions.
   */
  private Action[] my_option_menu_actions;
  
  /**
   * The list of actions for the tool bar and tool menu of the GUI.
   */
  private Action[] my_paint_tool_actions; 
  
  /**
   * The a container for the list of keyboard action. 
   */
  private Action[] my_kb_actions;
  
  /**
   * The timer that controls the movement of the ball.
   */
  private final Timer my_step_timer;

  /**
   * The CustomizKeys class needed to create a panel to customize user keys.
   */
  private final CustomizeKeys my_user_keys;
  
  /**
   * The container that all the tetris panels.  
   */
  private final TetrisFrame my_tetris_frame;
  
  /**
   * The content pane of the the tetris frame.
   */
  private final Container my_content_pane;
  
  /**
   * Used to indicate if the paint option is on, so the user can paint
   * on the panel.
   */
  private boolean my_paint_on;
  
  /**
   * Construst a tetris graphical user interface (GUI).
   */
  public TetrisGUI()
  {
    my_tetris_paint_panel = new TetrisPaintPanel(new BorderLayout());
    my_tetris_frame = new TetrisFrame();
    my_content_pane = my_tetris_frame.getContentPane();
    my_step_timer = new Timer(INITIAL_DELAY, new TetrisStepListener());
    my_tetris_board_panel = new TetrisBoardPanel(my_tetris_board);
    
    my_user_keys = new CustomizeKeys();
    my_board_list = new ArrayList<Board>();
    my_paint_on = false;
  }
  
  
  /**
   * Calls the setupCompnents to be initialized.
   */
  public void start() 
  {
    setupComponents();
  }
  
  
  /**
   * Sets up the components i.e. frames, panels, menus needed by the GUI.
   */
  private void setupComponents()
  {
    //Add actions 
    my_file_menu_actions = getFileMenuActions(my_tetris_board_panel, 
                                              my_step_timer, 
                                              my_tetris_paint_panel, 
                                              this);
    my_option_menu_actions = getOptionMenuActions(my_tetris_paint_panel);
    my_paint_tool_actions = getPaintToolActions(my_tetris_paint_panel);
    my_kb_actions = getKbActions(my_tetris_board, my_tetris_board_panel, my_step_timer);
    
    
    //Sets the panel to update 
    my_tetris_board.addObserver(my_tetris_board_panel);
    my_tetris_board_panel.setFocusable(true); 
    
    //Add menu bar and tool bar
    final JMenuBar menubar = createMenuBar();
    final PowerPaintToolBar toolbar = createTetrisPaintToolBar();
    
    //Add mouse listener to the GUI
    final MouseAdapter mouse_adapter = new ShapeGUIMouseAdapter();
    
    setUpTetrisPaintPanel(mouse_adapter, toolbar);
    setUpTetrisContentPane(mouse_adapter);
    assignKeys();
    setUpControls();

 
    my_tetris_frame.setJMenuBar(menubar);
    my_tetris_frame.setMinimumSize(MINIMUM_SIZE);
    my_tetris_frame.pack();
    my_tetris_frame.setVisible(true);
    
  }
  
  /**
   * Creates the actions needed for the file menu.
   * @param the_tetris_board_panel the tetris board panel to perform the action to.
   * @param the_step_timer  the timer to stop and start.
   * @param the_tetris_paint_panel  the tetris paint panel to perform the action to.
   * @param the_tetris_gui  the tetris board panel to perform the action to.
   * @return the actions for the file menu
   */
  private Action[] getFileMenuActions(final TetrisBoardPanel the_tetris_board_panel,
                                       final Timer the_step_timer, 
                                       final TetrisPaintPanel the_tetris_paint_panel,
                                       final TetrisGUI the_tetris_gui)
  {
    return new Action[]{
      
      new StartAction(the_step_timer, 
                      the_tetris_gui),             
      new EndGameAction(the_tetris_board_panel, 
                        the_tetris_gui),              
      new PracticeAction(this),
      new PauseAction(the_step_timer, the_tetris_board_panel),
      new ClearAction(the_tetris_paint_panel),
      new UndoAction(the_tetris_paint_panel),
      new QuitAction()
    };
  }
  
  /**
   * Creates the actions for the Option menu.
   * @param the_tetris_paint_panel the tetris paint panel to add actions to.
   * @return the actions for the thickness for the options menu.
   */
  private Action[] getOptionMenuActions(final TetrisPaintPanel the_tetris_paint_panel)
  {
    return new Action[]{  
      new ThicknessAction(ONE_PIXEL, the_tetris_paint_panel),
      new ThicknessAction(TWO_PIXEL, the_tetris_paint_panel),
      new ThicknessAction(FOUR_PIXEL, the_tetris_paint_panel),
      new ThicknessAction(EIGHT_PIXEL, the_tetris_paint_panel)    
    };
  }
  
  /**
   * Creates the actions for the Option menu.
   * @param the_tetris_paint_panel the tetris paint panel to add actions to.
   * @return the actions for the tetris paint tools.
   */
  private Action[] getPaintToolActions(final TetrisPaintPanel the_tetris_paint_panel)
  {
      
    return new Action[]{
      new ColorAction(the_tetris_paint_panel),
      new PencilAction(the_tetris_paint_panel),
      new LineAction(the_tetris_paint_panel),
      new RectangleAction(the_tetris_paint_panel),
      new EllipseAction(the_tetris_paint_panel),
      new ClearAction(the_tetris_paint_panel)
      
    };
  }
  
  /**
   * Creates the actions needed for keyboard to control the tetris game.
   * @param the_tetris_board the tetris board perform the action to.
   * @param the_tetris_board_panel the tetris board panel to perform the action to.
   * @param the_step_timer  the timer to stop and start.
   * @return the actions for the keyboard
   */
  private Action[] getKbActions(final Board the_tetris_board, 
                                 final TetrisBoardPanel the_tetris_board_panel,
                                 final Timer the_step_timer)
  {

    return new Action[]{
    
      
      new LeftAction(the_tetris_board), 
      new RightAction(the_tetris_board),
      new DownAction(the_tetris_board), 
      new RotateAction(the_tetris_board),
      new DropAction(the_tetris_board),
      new StartAction(the_step_timer, this), 
      new AboutAction(),
      new EndGameAction(the_tetris_board_panel, this),
      new PauseAction(the_step_timer, the_tetris_board_panel),
      new SwapPieceAction(the_tetris_board),
      new PracticeAction(this),
      new UndoPieceAction(the_tetris_board)
    };
  }
  
  /**
   * Creates the File menu for power paint GUI.
   * @return the File menu
   */
  private FileMenu createFileMenu()
  {
    final FileMenu filemenu = new FileMenu();
  
    for (Action a : my_file_menu_actions) 
    { 
      filemenu.createJMenuItem(a);
    }
    filemenu.insertSeparator(my_file_menu_actions.length - 1);
    return filemenu;
  }
  /**
   * Creates the Options menu for power paint.
   * @return the Options menu for power paint.
   */
  private OptionsMenu createOptionsMenu()
  {
    final OptionsMenu option_menu = new OptionsMenu();
    option_menu.createJCheckBoxMenuItem(new GridBaordAction(my_tetris_board_panel));
    option_menu.createJCheckBoxMenuItem(new DizzyAction(my_tetris_board_panel));
    option_menu.createJCheckBoxMenuItem(new PaintOnAction(my_tetris_paint_panel, this));
    option_menu.createJCheckBoxMenuItem(new GridAction(my_tetris_paint_panel, 
                                                        GRIDLINE_SPACING));
    option_menu.createJCheckBoxMenuItem(new ShowPanelAction(my_tetris_paint_panel,
                                                            Color.WHITE));
    
    final ThicknessMenu thickness_menu = new ThicknessMenu();
 
    for (Action a : my_option_menu_actions) 
    { 
      thickness_menu.createRadioButton(a);
    }
    
    final LevelMenu level_menu = new LevelMenu();
    for (int i = 1; i <= NUMBER_OF_LEVELS; i++)
    {
      level_menu.createRadioButton(new SelectLevelAction(my_tetris_board,
                                                         i,
                                                         my_tetris_board_panel));
    }
    option_menu.add(level_menu);
    option_menu.add(thickness_menu);
    option_menu.insertSeparator(2);
    return option_menu;
    
  }
  
  /**
   * Creates a ToolsMenu for the PowerPaint GUI.
   * @return the tools menu for the GUI
   */
  private ToolsMenu createToolsMenu()
  {
    final ToolsMenu tools_menu = new ToolsMenu();
    for (Action a : my_paint_tool_actions) 
    { 
      tools_menu.createRadioButton(a);
    }
    my_tetris_paint_panel.addItemToColor(tools_menu.getItem(0));
    my_tetris_paint_panel.selectColor(Color.GREEN);
    my_tetris_paint_panel.setmyThickness(INITIAL_PENCIL_THICKNESS);
    tools_menu.insertSeparator(1);
    return tools_menu;
  }
  

  
  /**
   * Creates the help menu for the power paint gui.
   * @return The help menu for the power paint gui.
   */
  private HelpMenu createHelpMenu()
  {
    final HelpMenu helpmenu = new HelpMenu();
    final Action[] help_actions = {
      new AboutAction(),
      new CustomizeKeysAction(my_user_keys.getKeySelector())
    };
  
    
    for (Action a : help_actions) 
    { 
      helpmenu.createJMenuItem(a);
    }
    
    return helpmenu;
  }
  /**
   * Creates a PowerPaintToolBar for the PowerPaint GUI.
   * @return the tool bar for the GUI.
   */
  private PowerPaintToolBar createTetrisPaintToolBar()
  {
    final PowerPaintToolBar tool_bar = new PowerPaintToolBar();
    for (Action a : my_paint_tool_actions) 
    { 
      tool_bar.createToggleButton(a);
    }
    
    //tool_bar.createToggleButton(new PauseAction(my_step_timer, my_game_panel));
    my_tetris_paint_panel.addItemToColor((JComponent) tool_bar.getComponent(0));
    my_tetris_paint_panel.selectColor(Color.GREEN);
    return tool_bar;
  }
  
  /**
   * Creates the menu bar for the tetris frame.
   * @return the tetris bar for the frame.
   */
  private JMenuBar createMenuBar()
  {
    final JMenuBar menubar = new JMenuBar();
    final FileMenu file_menu = createFileMenu();
    final OptionsMenu option_menu = createOptionsMenu();
    final ToolsMenu toolmenu = createToolsMenu();
    final HelpMenu help_menu = createHelpMenu();
    
    menubar.add(file_menu);
    menubar.add(option_menu);
    menubar.add(toolmenu);
    menubar.add(help_menu);
    
    return menubar;
  }
  
  /**
   * Create the tetris buttons for the tetris content pane.
   * @return the button panel for the content pane.
   */
  private JPanel createTetrisButtons()
  {
    final JButton button1 = new JButton(my_kb_actions[START_GAME]);
    final JButton button2 = new JButton(my_kb_actions[UNDO]);
    final JToggleButton button3 = new JToggleButton(my_kb_actions[PAUSE]);
    button3.setSelected(false);
    final JButton button4 = new JButton(my_kb_actions[SWAP]);
    final JPanel north_panel = new JPanel(new GridLayout(1, NUMBER_OF_TETRIS_BUTTONS));
    north_panel.add(button1);
    north_panel.add(button2);
    north_panel.add(button3);
    north_panel.add(button4);
    return north_panel;
  }
  
  /**
   * Sets up the tetris paint panel.
   * @param the_mouse_adapter the mouse adapter to listen to movement in the paint panel.
   * @param the_tetris_paint_toolbar the tool bar to add to the paint panel.
   */
  private void setUpTetrisPaintPanel(final MouseAdapter the_mouse_adapter, 
                                       final PowerPaintToolBar the_tetris_paint_toolbar)
  
  {
    my_tetris_paint_panel.addMouseListener(the_mouse_adapter);
    my_tetris_paint_panel.addMouseMotionListener(the_mouse_adapter);
    
    //Initialize the tetris paint panel to start with pencil selected and adds the tool bar.
    my_tetris_paint_panel.drawPencil();
    my_tetris_paint_panel.add(the_tetris_paint_toolbar, BorderLayout.SOUTH);
    my_tetris_frame.setGlassPane(my_tetris_paint_panel);
    my_tetris_paint_panel.setOpaque(false);
    
  }
  
  /**
   * Sets up the tetris content pane.
   * @param the_mouse_adapter the mouse adapter to listen to movement in the content pane.
   */
  private void setUpTetrisContentPane(final MouseAdapter the_mouse_adapter)
  {

    final JPanel north_panel_buttons = createTetrisButtons(); 
    my_content_pane.add(north_panel_buttons, BorderLayout.NORTH);
    my_content_pane.addMouseListener(the_mouse_adapter);
    my_content_pane.addMouseMotionListener(the_mouse_adapter);
    my_content_pane.add(my_tetris_board_panel, BorderLayout.CENTER);
    
  }

  
  /**
   * Sets up the default keyboard controls for the tetris program.
   */
  private void setUpControls()
  {
    /*
     * The strings appear twice because these are keys used to assign a keyboard
     * key to the the action map.
     */
    my_tetris_board_panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), 
                                    "MOVE LEFT");    
    my_tetris_board_panel.getActionMap().put("MOVE LEFT", my_kb_actions[LEFT]); 
    
    my_tetris_board_panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
                                    "MOVE RIGHT");    
    my_tetris_board_panel.getActionMap().put("MOVE RIGHT", my_kb_actions[RIGHT]);
    
    my_tetris_board_panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
                                    "MOVE DOWN");    
    my_tetris_board_panel.getActionMap().put("MOVE DOWN", my_kb_actions[DOWN]); 
    
    my_tetris_board_panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), 
                                    "ROTATE");    
    my_tetris_board_panel.getActionMap().put("ROTATE", my_kb_actions[ROTATE]);
    
    my_tetris_board_panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), 
                                    "DROP");    
    my_tetris_board_panel.getActionMap().put("DROP", my_kb_actions[DROP]);
    
    
    my_tetris_board_panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), 
        "Start Game");

    my_tetris_board_panel.getActionMap().put("Start Game", my_kb_actions[START_GAME]); 
    
    my_tetris_board_panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0),
            "Open help");    
    my_tetris_board_panel.getActionMap().put("Open help", my_kb_actions[ABOUT]);
        
    my_tetris_board_panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_0, 0), 
                                    "END THE GAME");    
    my_tetris_board_panel.getActionMap().put("END THE GAME", my_kb_actions[END]);
    
    my_tetris_board_panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_P , 0), 
        "PAUSE");    
    my_tetris_board_panel.getActionMap().put("PAUSE",  my_kb_actions[PAUSE]);
    
    my_tetris_board_panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_S , 0), 
        "SWAP PIECE");    
    my_tetris_board_panel.getActionMap().put("SWAP PIECE",  my_kb_actions[SWAP]);
    
    my_tetris_board_panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE , 0), 
        "PRACTICE MODE");    
    my_tetris_board_panel.getActionMap().put("PRACTICE MODE",  my_kb_actions[PRACTICE]);
    
    my_tetris_board_panel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), 
        "UNDO PIECE");    
    my_tetris_board_panel.getActionMap().put("UNDO PIECE",  my_kb_actions[UNDO]);
    
  }

  /**
   * Assign actions to keys.
   */
  private void assignKeys()
  {
    for (int i = 1; i <= NUMBER_OF_USER_ASSIGNED_KEYS; i++)
    { 
      my_user_keys.setButtonAction(i, new AssignKeyAction(my_user_keys.getTextField(i), 
                                          my_tetris_board_panel, my_kb_actions[i - 1]));   
    }
  }

  
  /**
   * Saves the board to a list of tetris board.
   */
  public void saveBoard()
  {
    my_step_timer.stop();
    my_board_list.add(my_tetris_board);
    my_tetris_board = new Board(TETRIS_BOARD_HEIGHT, TETRIS_BOARD_WIDTH);
    final int x = my_tetris_frame.getX();
    final int y = my_tetris_frame.getY();
    my_tetris_frame.dispose(); 
    start();
    my_tetris_frame.setLocation(x, y);
    my_tetris_board_panel.requestFocus();
  }
  
  /**
   * Loads the board from the index given.
   * @param the_index the index to get the saved board from.
   */
  public void loadBoard(final int the_index)
  {
    if (!my_board_list.isEmpty()) 
    {
      my_tetris_board = my_board_list.get(the_index);
      final int x = my_tetris_frame.getX();
      final int y = my_tetris_frame.getY();
      my_tetris_frame.dispose();
      start();
      my_tetris_board_panel.setInitialState(false);
      my_tetris_board_panel.repaint();
      my_tetris_frame.setLocation(x, y);
      my_step_timer.start();
      my_tetris_board_panel.requestFocus();
      
    }
    
  }
  
  /**
   * Retrieves the list of board that were saved.
   * @return the list of saved boards.
   */
  public List<Board> getMyBoardList()
  {
    return my_board_list;
  }
  
  /**
   * Resets the TetrisGUI to an initial state.
   */
  public void restGUI()
  {
    my_tetris_board.clearAllLines();
    my_tetris_board.setGameOver(false);
    my_tetris_board.setScore(0);
    my_tetris_board.setNumberOfLinesCleared(0);
    my_tetris_board.setSwapPiece(null);
    my_tetris_board_panel.setBackground(Color.GRAY);
    my_tetris_board_panel.setPause(false);
    my_tetris_board_panel.setInitialState(false);
    my_tetris_board_panel.setFocusable(true);
    my_tetris_board_panel.requestFocus();
    this.resetTimer();
  }
  
  
  /**
   * This method resets the timer to the initial dealy.
   */
  public final void resetTimer()
  {
    my_step_timer.setDelay(INITIAL_DELAY);
    my_step_timer.stop(); 
  }
  
  /**
   * Enables panel to be painted or drawn on.
   * @param the_paint_on whether to gave paint on (true) or have it off(false)
   */
  public void setPaintOn(final boolean the_paint_on)
  {
    my_paint_on = the_paint_on;
  }
  /**
   * This inner class is used by the Power Paint program to listen to mouse events.
   * @author Alvin Baldemeca
   * @version 5/10/2012
   */
  public class ShapeGUIMouseAdapter extends MouseAdapter 
  {
    @Override
    public void mousePressed(final MouseEvent the_event) 
    {
      if (my_paint_on)
      {
        my_tetris_paint_panel.recordStartPoint(the_event.getPoint());
      }

    }

    @Override
    public void mouseDragged(final MouseEvent the_event) 
    {
      if (my_paint_on)
      {
        my_tetris_paint_panel.recordDragPoint(the_event.getPoint());
        my_tetris_board_panel.requestFocus();
      }
    }
    
    @Override
    public void mouseReleased(final MouseEvent the_event)
    {
      if (my_paint_on)
      {
        my_tetris_paint_panel.addShape();
        my_tetris_board_panel.requestFocus();
      }
    }
    
    @Override
    public void mouseMoved(final MouseEvent the_event)
    {
      if (my_paint_on)
      {
        my_tetris_board_panel.requestFocus();
        final Point mouse = the_event.getPoint();
        
        if (mouse.y < FOCUS_Y)
        {
          my_tetris_paint_panel.setVisible(false);
        }
        else
        {
          my_tetris_paint_panel.setVisible(true);
        }
      }
      // System.out.println("X = " + the_event.getX() + "Y = " +the_event.getY());
    }
    
    @Override
    public void mouseExited(final MouseEvent the_event)
    {
      my_tetris_board_panel.requestFocus();
    }


    
  }
  
  
  /**
   * This is a private class used by the timer class to perform an action.
   * @author Alvin Baldemeca
   * @version 5/24/2012
   */
  private class TetrisStepListener implements ActionListener 
  {
    @Override
    public void actionPerformed(final ActionEvent the_event) 
    {
      my_tetris_board.step();
      my_tetris_board.freezePiece(true);
      my_tetris_board.freezePiece(false);
      if (my_step_timer.getDelay() <= SPEED_UP)
      {
        my_tetris_board_panel.setDizzy(true);
        my_step_timer.setDelay(NEXT_LEVEL);
      }
      else
      {
        
      
        final int numb = my_tetris_board.getNumberOfLinesCleared() / NEXT_LEVEL;
        my_step_timer.setDelay(INITIAL_DELAY - (numb * SPEED_UP));
      
      }

    }
  }

  
  
}
